<?php

namespace app\swoole;

use Swoole\Server;
use Swoole\Websocket\Frame;
use Swoole\WebSocket\Server as WebsocketServer;
use think\Config;
use think\facade\Cache;
use think\Request;
use think\swoole\contract\websocket\HandlerInterface;
use think\swoole\websocket\socketio\Packet;

class Handler implements HandlerInterface
{
    /** @var WebsocketServer */
    protected $server;

    /** @var Config */
    protected $config;

    public function __construct(Server $server, Config $config)
    {
        $this->server = $server;
        $this->config = $config;
    }

    /**
     * "onOpen" listener.
     *
     * @param int     $fd
     * @param Request $request
     */
    public function onOpen($fd, Request $request)
    {
        $token = $request->cookie('token');
        if(!$token){
            $data = [
                'status' => 0,
            ];
            $this->server->push($fd,json_encode($data));
        }
        $userData = Cache::store('redis')->get('users'.$token);

        // 判断是否存在
        if(!$userData){
            $data = [
                'status' => 0,
            ];
            $this->server->push($fd,json_encode($data));
        }else{
            $data = [
                'nickname' => $userData['nickname'],
                'avatar' => $userData['avatar'],
                'status' => 1,
                'type' => 3,
            ];
    
            // 绑定fd
            $userData['fd'] = $fd;
            Cache::store('redis')->set('users'.$token,$userData);
            // 写入列表
            Cache::store('redis')->setnx('online_user'.$fd,serialize($userData));
            // // 读取在线用户
            $data['online_users'] = $this->getUserList();
            foreach ($this->server->connections as $fd) {
                if ($this->server->isEstablished($fd)) {
                    $this->server->push($fd,json_encode($data));
                }
            }
        }
    }

    /**
     * "onMessage" listener.
     *  only triggered when event handler not found
     *
     * @param Frame $frame
     * @return bool
     */
    public function onMessage(Frame $frame)
    {
        $wsData = json_decode($frame->data,1);
        if(isset($wsData['token'])){
            $userData = Cache::store('redis')->get('users'.$wsData['token']);
        }

        if(!$userData){
            $data = [
                'type' => 6,
            ];
            $this->server->push($frame->fd,json_encode($data));
        }else{
            $data = [
                'avatar' => isset($userData['avatar'])?$userData['avatar']:rand(1000,10000),
                'nickname' => isset($userData['nickname'])?$userData['nickname']:rand(1000,10000),
                'message' => $wsData['message'],
                'time' => date('Y-m-d H:i:s',time()),
                'status' => 1,
                'fd' => $frame->fd,
                'token' => $wsData['token'],
            ];
    
            // 判断用户或群聊
            if($wsData['send_token']){
                
                $sendUserData = Cache::store('redis')->get('online_user'.$wsData['fd']);
                if(!$sendUserData){
                    $data = [
                        'type' => 4,
                        'fd' => $wsData['fd'],
                        'token' => $wsData['send_token'],
                    ];
                    $this->server->push($frame->fd,json_encode($data));
                }else{
                    $data['type'] = 2;
                    echo '发送给:'.$sendUserData['nickname'].PHP_EOL;
                    $this->server->push($sendUserData['fd'],json_encode($data));
                }
            }else{
                $data['type'] = 5;
                foreach ($this->server->connections as $fd) {
                    // 需要先判断是否是正确的websocket连接，否则有可能会push失败
                    if ($this->server->isEstablished($fd) && $fd != $frame->fd) {
                        $this->server->push($fd,json_encode($data));
                    }
                }
            }
        }
        return true;
    }

    /**
     * "onClose" listener.
     *
     * @param int $fd
     * @param int $reactorId
     */
    public function onClose($fd, $reactorId)
    {
        // 用户下线
        echo $fd.'下线'.PHP_EOL;
        Cache::store('redis')->del('online_user'.$fd);
        // 更新用户列表
        $data = [
            'status' => 2,
            'type' => 3,
        ];
        $data['online_users'] = $this->getUserList();
        $this->updateUserData($data);
    }

    protected function checkHeartbeat($fd, $packet)
    {
        $packetLength = strlen($packet);
        $payload      = '';

        if ($isPing = Packet::isSocketType($packet, 'ping')) {
            $payload .= Packet::PONG;
        }

        if ($isPing && $packetLength > 1) {
            $payload .= substr($packet, 1, $packetLength - 1);
        }

        if ($isPing) {
            $this->server->push($fd, $payload);
        }
    }

    // 获取用户列表
    public function getUserList()
    {
        // // 读取在线用户
        $onLineUsers = [];
        $list = Cache::store('redis')->keys('online_user*');
        foreach($list as $user){
            $onLineUsers[] = Cache::store('redis')->get($user);
        }
        return $onLineUsers;
    }
    
    // 更新所有用户数据
    public function updateUserData($data)
    {
        $onLineUsers = $this->getUserList();
        foreach ($onLineUsers as $user) {
            $userInfo = $user;
            $this->server->push($userInfo['fd'],json_encode($data));
        }
    }

}